/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2025. All rights reserved.
 */

import { levels } from 'log4js';
import { clean } from 'semver';

import {
  HVIGOR_MEMORY_THRESHOLD,
  HVIGOR_POOL_CACHE_CAPACITY,
  HVIGOR_POOL_CACHE_TTL,
  HVIGOR_POOL_MAX_CORE_SIZE,
  HVIGOR_POOL_MAX_SIZE,
  OHOS_ARK_COMPILE_MAX_SIZE,
} from '../../../common/const/const.js';
import { HvigorConfigLoader } from '../../../common/util/hvigor-config-loader.js';
import { hvigorTrace } from '../../common/trace/hvigor-trace.js';
import { levelMap } from '../../log/default-configuration.js';
import { HvigorLogger } from '../../log/hvigor-log.js';
import { HvigorConfig, HvigorConfigReader } from '../../util/hvigor-config-reader.js';
import { HvigorCliOptions } from '../../util/options/hvigor-cli-options.js';
import { coreParameter, defaultProperties, OptimizationStrategy } from './global-core-parameters.js';


/**
 * 保存cli生命周期中常用的全局数据
 *
 * @since 2022/8/17
 */
class GlobalData {
  public cliEnv: any;
  public cliOpts!: HvigorCliOptions;
  public buildId: string | undefined;

  init(cliEnv: any, cliOpts: HvigorCliOptions) {
    this.cliEnv = cliEnv;
    this.cliOpts = cliOpts;
    this.buildId = createBuildId();
    hvigorTrace.traceBuildId(this.buildId);
  }

  /**
   * 每次构建结束显式的清除数据 (目前只有buildId有必要)
   */
  clean() {
    this.buildId = undefined;
  }
}

export const globalData = new GlobalData();

/**
 * ./hvigorw test 命令行默认props
 */
const defaultTestProps: Record<string, string> = {
  pageType: 'page',
  product: 'default',
  buildRoot: '.test',
  unitTestMode: 'true',
  isLocalTest: 'true',
  'ohos-test-coverage': 'true',
  'unit.test.replace.page': '../../../.test/testability/pages/Index',
};

const defaultDeviceTestProps: Record<string, string> = {
  product: 'default',
  buildMode: 'test',
  isOhosTest: 'true',
  'ohos-test-coverage': 'true',
};

export interface StartEnvironment {
  nodeHome: string;
  workspaceDir: string;
}

export const defaultStartEnvironment: StartEnvironment = {
  nodeHome: process.env.NODE_HOME ?? '',
  workspaceDir: process.env.WORKSPACE_DIR ?? '',
};

export let startEnvironment: StartEnvironment = { ...defaultStartEnvironment };

export function initStartData(hvigorCliOptions?: HvigorCliOptions) {
  HvigorConfigLoader.init(hvigorCliOptions);
  HvigorLogger.clean();
  initExtParam(hvigorCliOptions);
  initParamProperties();
  mergeHvigorConfig();
  setTestDefaultParameters(hvigorCliOptions);
  setDeviceTestDefaultParameters(hvigorCliOptions);
  mergeCliConfig(hvigorCliOptions);
  initParamProperties();
  traceHvigorConfigProperties();
}

/**
 * 刷新daemon进程中的环境变量
 *
 * @param {HvigorCliOptions} cliOptions 命令行参数对象
 */
export function refreshDaemonProcessEnv(cliOptions: HvigorCliOptions) {
  if (!cliOptions.env) {
    return;
  }

  // 处理daemon模式下,修改SDK环境变量不生效问题
  process.env.DEVECO_SDK_HOME = cliOptions.env.DEVECO_SDK_HOME ?? '';
  process.env.OHOS_BASE_SDK_HOME = cliOptions.env.OHOS_BASE_SDK_HOME ?? '';
}

function initExtParam(hvigorCliOptions?: HvigorCliOptions) {
  if (!hvigorCliOptions) {
    return;
  }

  const properties = new Map<string, string>();
  if (hvigorCliOptions.prop !== undefined) {
    [hvigorCliOptions.prop].flat(2).forEach((value: string) => {
      const arr = value.split('=');
      properties.set(arr[0], arr?.splice(1)?.join('='));
    });
  }

  coreParameter.extParams = Object.fromEntries(properties.entries());
  coreParameter.workspaceDir = startEnvironment.workspaceDir;
}

function initParamProperties() {
  const hvigorConfigLoader = HvigorConfigLoader.getInstance();
  coreParameter.properties.hvigorPoolMaxSize = regularizeNumber(hvigorConfigLoader.getPropertiesConfigValue<number>(HVIGOR_POOL_MAX_SIZE));
  coreParameter.properties.hvigorPoolMaxCoreSize = regularizeNumber(hvigorConfigLoader.getPropertiesConfigValue<number>(HVIGOR_POOL_MAX_CORE_SIZE));
  coreParameter.properties.hvigorPoolCacheCapacity = regularizeNumber(hvigorConfigLoader.getPropertiesConfigValue<number>(HVIGOR_POOL_CACHE_CAPACITY));
  coreParameter.properties.hvigorPoolCacheTtl = regularizeNumber(hvigorConfigLoader.getPropertiesConfigValue<number>(HVIGOR_POOL_CACHE_TTL));
  coreParameter.properties.ohosArkCompileMaxSize = regularizeNumber(hvigorConfigLoader.getPropertiesConfigValue<number>(OHOS_ARK_COMPILE_MAX_SIZE));
  coreParameter.properties.hvigorMemoryThreshold = regularizeNumber(hvigorConfigLoader.getPropertiesConfigValue<number>(HVIGOR_MEMORY_THRESHOLD));
}

function regularizeNumber(x: string | number | undefined) {
  if (typeof x === 'string' || x === undefined || x < 0) {
    return undefined;
  }
  return Math.floor(x);
}

function getPropMap(prop?: string | string[]) {
  const map: Map<string, string> = new Map();
  if (!prop) {
    return map;
  }
  const props = typeof prop === 'string' ? [prop] : prop;
  props.forEach((prop) => {
    const [key, value] = prop.split('=');
    const finalKey = key === 'coverage' ? 'ohos-test-coverage' : key;
    map.set(finalKey, value);
  });
  return map;
}

/**
 * 针对 ./hvigorw test做一些默认值设置
 */
function setTestDefaultParameters(hvigorCliOptions?: HvigorCliOptions) {
  if (!hvigorCliOptions) {
    return;
  }

  // 判断是否是test
  const isTest = hvigorCliOptions._.includes('test');
  if (!isTest) {
    return;
  }
  if (!hvigorCliOptions.mode) {
    hvigorCliOptions.mode = 'module';
  }
  const propMap = getPropMap(hvigorCliOptions.prop);
  Object.keys(defaultTestProps).forEach((key) => {
    if (propMap.has(key)) {
      return;
    }
    propMap.set(key, defaultTestProps[key]);
  });
  const props: string[] = [];
  propMap.forEach((value, key) => {
    props.push(`${key}=${value}`);
  });
  hvigorCliOptions.prop = props;
}

function setDeviceTestDefaultParameters(hvigorCliOptions?: HvigorCliOptions) {
  if (!hvigorCliOptions) {
    return;
  }

  // 判断是否是onDeviceTest
  const isDeviceTest = hvigorCliOptions._.includes('onDeviceTest');
  if (!isDeviceTest) {
    return;
  }
  if (!hvigorCliOptions.mode) {
    hvigorCliOptions.mode = 'module';
  }
  const propMap = getPropMap(hvigorCliOptions.prop);
  Object.keys(defaultDeviceTestProps).forEach((key) => {
    if (propMap.has(key)) {
      return;
    }
    propMap.set(key, defaultDeviceTestProps[key]);
  });
  const props: string[] = [];
  propMap.forEach((value, key) => {
    props.push(`${key}=${value}`);
  });
  hvigorCliOptions.prop = props;
}

export function resetStartData() {
  startEnvironment = { ...defaultStartEnvironment };
  coreParameter.clean();
}

function mergeHvigorConfig() {
  const hvigorConfig: HvigorConfig | undefined = HvigorConfigReader.getHvigorConfig();

  if (!hvigorConfig) {
    coreParameter.properties = {
      ...defaultProperties,
      ...coreParameter.properties,
    };
    return;
  }
  startEnvironment = { ...startEnvironment, ...hvigorConfig.environment };
  coreParameter.properties = {
    ...defaultProperties,
    ...hvigorConfig.properties,
    ...coreParameter.properties,
  };
  setStartParameters(hvigorConfig);
}

// 修改mergeHvigorConfig方法圈复杂度超过20
function setStartParameters(hvigorConfig: HvigorConfig) {
  coreParameter.startParams.incrementalExecution = hvigorConfig.execution?.incremental ?? coreParameter.startParams.incrementalExecution;
  coreParameter.startParams.hvigorfileTypeCheck = hvigorConfig.execution?.typeCheck ?? coreParameter.startParams.hvigorfileTypeCheck;
  coreParameter.startParams.parallelExecution = hvigorConfig.execution?.parallel ?? coreParameter.startParams.parallelExecution;
  coreParameter.startParams.daemon = hvigorConfig.execution?.daemon ?? coreParameter.startParams.daemon;
  coreParameter.startParams.printStackTrace = hvigorConfig.debugging?.stacktrace ?? coreParameter.startParams.printStackTrace;
  coreParameter.startParams.optimizationStrategy = hvigorConfig.execution?.optimizationStrategy ?? coreParameter.startParams.optimizationStrategy;
  fillLoggingParameters(hvigorConfig);
}

function fillLoggingParameters(hvigorConfig: HvigorConfig) {
  if (hvigorConfig.logging?.level) {
    coreParameter.startParams.logLevel = levelMap.get(hvigorConfig.logging?.level) ?? coreParameter.startParams.logLevel;
  }
}

function mergeCliConfig(hvigorCliOptions?: HvigorCliOptions) {
  const opts = hvigorCliOptions ?? globalData.cliOpts;
  startEnvironment.nodeHome = opts.nodeHome ?? startEnvironment.nodeHome;
  coreParameter.startParams.hotCompile = opts.hotCompile;
  coreParameter.startParams.hotReloadBuild = opts.hotReloadBuild;
  coreParameter.startParams.hvigorfileTypeCheck = opts.enableBuildScriptTypeCheck ?? coreParameter.startParams.hvigorfileTypeCheck;
  coreParameter.startParams.hvigorfileTypeCheck = opts.typeCheck ?? coreParameter.startParams.hvigorfileTypeCheck;
  coreParameter.startParams.daemon = opts.daemon ?? coreParameter.startParams.daemon;
  coreParameter.startParams.printStackTrace = opts.stacktrace ?? coreParameter.startParams.printStackTrace;
  coreParameter.startParams.logLevel = opts.debug
    ? levels.DEBUG
    : opts.warn
      ? levels.WARN
      : opts.error
        ? levels.ERROR
        : opts.info
          ? levels.INFO
          : coreParameter.startParams.logLevel;
  coreParameter.startParams.parallelExecution = opts.parallel ?? coreParameter.startParams.parallelExecution;
  coreParameter.startParams.incrementalExecution = opts.incremental ?? coreParameter.startParams.incrementalExecution;
  coreParameter.startParams.optimizationStrategy =
    opts.optimizationStrategy && Object.values(OptimizationStrategy).includes(opts.optimizationStrategy as OptimizationStrategy)
      ? opts.optimizationStrategy
      : coreParameter.startParams.optimizationStrategy;
  hvigorTrace.traceBaseConfig(
    coreParameter.startParams.incrementalExecution,
    coreParameter.startParams.daemon,
    coreParameter.startParams.parallelExecution,
    coreParameter.startParams.hvigorfileTypeCheck,
  );
}

/**
 * 根据时间以及report目录下的文件为每次构建创建一个独一无二的buildId
 * 因为时间精度直到毫秒，所以最后一位添加一个计数位，如果同一毫秒内调用了两次 会通过最后一位区分开
 *
 */
let lastTimestamp = '';
let counter = 0;

function createBuildId() {
  const date = new Date();

  // 获取当前时间戳 单位为毫秒
  const year = date.getFullYear();
  const month = `0${date.getMonth() + 1}`.slice(-2);
  const day = `0${date.getDate()}`.slice(-2);
  const hours = `0${date.getHours()}`.slice(-2);
  const minutes = `0${date.getMinutes()}`.slice(-2);
  const seconds = `0${date.getSeconds()}`.slice(-2);
  const mills = `00${date.getMilliseconds()}`.slice(-3);
  const currentTimestamp = `${year}${month}${day}${hours}${minutes}${seconds}${mills}`;

  // 当本次调用和上次调用的时间戳不同，则将标志位归零
  if (currentTimestamp !== lastTimestamp) {
    lastTimestamp = currentTimestamp;
    counter = 0;
  } else {
    counter++;
  }
  return `${currentTimestamp}${counter}`;
}
function traceHvigorConfigProperties() {
  const configProperties = Object.fromEntries(Object.entries(coreParameter.properties).filter(([key, value]) => value !== undefined));
  hvigorTrace.traceConfigProperties(configProperties);
}
